﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "ElevationViewSymbolNew.h"
#include "ElevationViewSymbolNewBehaviors.h"

#include "NdbObjectSchematic.h"
#include "DbObjectUtils.h"
#include "OwnerPtr.h"
#include "IGenericElement.h"
#include "IElementBasicInformation.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "IElementParentReporter.h"
#include "IGraphicsElementShape.h"
#include "IModelView.h"
#include "IViewClipRange.h"
#include "IDocument.h"
#include "Vector3d.h"
#include "AlgorithmProject.h"
#include "IPlane.h"
#include "IGraphicsArc.h"
#include "IGraphicsLine.h"
#include "IGraphicsText.h"
#include "Vector3dUtils.h"
#include "AnchorAlignmentType.h"
#include "TextPrimitiveType.h"
#include "ILine3d.h"
#include "AlgorithmMinimalDistance.h"
#include "Vector2dUtils.h"
#include "MathUtils.h"
#include "IModelViewEventArgs.h"
#include "IModelViewEvent.h"
#include "IElementPositionPoints.h"
#include "IRegeneratorDataIdCreator.h"
#include "IRegenerator.h"
#include "IElementParameters.h"
#include "IGraphicsStyleManager.h"
#include "ImplementationUidTreeRegister.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

const double ElevationViewSymbolNewCircleRadius = 580;
const double ElevationViewSymbolNewTriangleCathetus = 1200;
const double ElevationViewSymbolNewFontsHeight = 514;  //由于GText替换为GTextEx后会导致字形显示变大，此处为了基本达到原有的大小*0.735,700*0.735,此处的0.735为经验值

namespace {

    class AssociatedModelViewEventHandler : public IModelViewEventHandler
    {
    public:
        AssociatedModelViewEventHandler(ElevationViewSymbolNew* pViewSymbol)
            : m_pViewSymbol(pViewSymbol)
        {
        }

        ~AssociatedModelViewEventHandler()
        {
        }

        virtual void On(IModelViewEventArgs* pArgs) override
        {
            if (!pArgs || !m_pViewSymbol || !m_pViewSymbol->GetDocument())
                return;

            if (pArgs->GetType() == ModelViewEventType::NameChanged)
            {
                bool bMatch = (m_pViewSymbol->GetDocument()->GetRuntimeId() == pArgs->GetDocumentRuntimeId() &&
                    m_pViewSymbol->GetModelViewId() == pArgs->GetModelViewId());
                DBG_WARN_AND_RETURN_VOID_UNLESS(bMatch, L"事件不参数不匹配",L"GDMPLab",L"2024-03-30");

                const IModelView* pModelView = quick_cast<const IModelView>(m_pViewSymbol->GetDocument()->GetElement(m_pViewSymbol->GetModelViewId()));
                DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");

                m_pViewSymbol->MarkChanged();
            }
        }
    private:
        ElevationViewSymbolNew* m_pViewSymbol;
    };
}

namespace gcmp{

    // 立面视图标志的控制点行为
    class ElevationViewSymbolNewPositionPoints : public NdbObjectSchematic, public IElementPositionPoints
    {
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(gcmp, ElevationViewSymbolNewPositionPoints, gcmp::NdbObjectSchematic, 56898FE2 - 7914 - 4A16 - A390 - 76EECC47919C, gbmpmodel, gcmp::IElementPositionPoints)
            DATA(OwnerPtr<IElementPositionPoints>, DefaultPositonPoints)
            DBOBJECT_DATA_END

    public:
        ElevationViewSymbolNewPositionPoints(IElement * pElement)
        {
            SetDefaultPositonPoints__(IElementPositionPoints::CreateBaseOnElementPosition(pElement));
        }

    private:
        enum class AuxiliaryPointStartEndPointType
        {
            None,
            StartPointType,
            EndPointType
        };

#pragma region IElementPositionPoints 接口
    public:
        virtual int GetControlPointCount() const override
        {
            const IElementPositionPoints* pDefaultPositonPoints = GetDefaultPositonPoints();
            DBG_WARN_AND_RETURN_UNLESS(pDefaultPositonPoints, 0, L"invalid pDefaultPositonPoints",L"GDMPLab",L"2024-03-30");
            return pDefaultPositonPoints->GetControlPointCount();
        }
        virtual RegenDataId GetControlPointRdId(int index) const override
        {
            const IElementPositionPoints* pDefaultPositonPoints = GetDefaultPositonPoints();
            DBG_WARN_AND_RETURN_UNLESS(pDefaultPositonPoints, RegenDataId(), L"invalid pDefaultPositonPoints",L"GDMPLab",L"2024-03-30");
            return pDefaultPositonPoints->GetControlPointRdId(index);
        }
        virtual void MarkControlPointRdId(int index) override
        {
            IElementPositionPoints* pDefaultPositonPoints = GetDefaultPositonPoints();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pDefaultPositonPoints, L"invalid pDefaultPositonPoints",L"GDMPLab",L"2024-03-30");
            return pDefaultPositonPoints->MarkControlPointRdId(index);
        }
        virtual bool SetOwnerElement(IElement* pOwnerElement) override
        {
            IElementPositionPoints* pDefaultPositonPoints = GetDefaultPositonPoints();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pDefaultPositonPoints, L"invalid pDefaultPositonPoints",L"GDMPLab",L"2024-03-30");
            return pDefaultPositonPoints->SetOwnerElement(pOwnerElement);
        }
        virtual IElement* GetOwnerElement() override
        {
            IElementPositionPoints* pDefaultPositonPoints = GetDefaultPositonPoints();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDefaultPositonPoints, L"invalid pDefaultPositonPoints",L"GDMPLab",L"2024-03-30");
            return pDefaultPositonPoints->GetOwnerElement();
        }
        virtual const IElement* GetOwnerElement() const override
        {
            const IElementPositionPoints* pDefaultPositonPoints = GetDefaultPositonPoints();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDefaultPositonPoints, L"invalid pDefaultPositonPoints",L"GDMPLab",L"2024-03-30");
            return pDefaultPositonPoints->GetOwnerElement();
        }

        virtual Vector3d GetControlPoint(int pointIndex) const override
        {
            Vector3d ret = Vector3d::Zero;

            IModelView *pElevationModelView = GetElevationModelViewOfOwnerSymbol();
            DBG_WARN_AND_RETURN_UNLESS(pElevationModelView, ret, L"invalid pElevationModelView",L"GDMPLab",L"2024-03-30");
            IViewClipRange* pViewClipRange = IViewClipRange::GetViewClipRange(pElevationModelView->GetDocument(), pElevationModelView->GetViewClipRangeId());

            const Vector3d origin = pElevationModelView->GetOrigin();
            Vector3d dirRight = pElevationModelView->GetRightDirection();
            dirRight.Normalize();

            double viewPortLeftOffset;
            double viewPortRightOffset;
            double uselessOffset;
            {
                bool bOk = pViewClipRange->GetRectViewClipRange(viewPortLeftOffset, viewPortRightOffset, uselessOffset, uselessOffset);
                DBG_WARN_AND_RETURN_UNLESS(bOk, ret, L"Fail GetDefaultRectViewport",L"GDMPLab",L"2024-03-30");
            }

            //立面视图标记起点（夹点）：视图方向左侧
            //立面视图标记终点（夹点）：视图方向右侧
            if (AuxiliaryPointStartEndPointType::StartPointType == (AuxiliaryPointStartEndPointType)pointIndex)
            {
                ret = origin + (-dirRight)*viewPortLeftOffset;
            }
            else if (AuxiliaryPointStartEndPointType::EndPointType == (AuxiliaryPointStartEndPointType)pointIndex)
            {
                ret = origin + dirRight*viewPortRightOffset;
            }
            return ret;
        }

        virtual void SetControlPoint(int pointIndex, const Vector3d& pos) override
        {
            //立面视图标记起点（夹点）：视图方向左侧
            //立面视图标记终点（夹点）：视图方向右侧
            Vector3d ret = Vector3d::Zero;
            IModelView *pElevationModelView = GetElevationModelViewOfOwnerSymbol();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pElevationModelView, L"invalid pElevationModelView",L"GDMPLab",L"2024-03-30");
            IViewClipRange* pViewClipRange = IViewClipRange::GetViewClipRange(pElevationModelView->GetDocument(), pElevationModelView->GetViewClipRangeId());
            //立面视图视点（原点）
            const Vector3d elevationViewOrigin = pElevationModelView->GetOrigin();
            //立面视图视图方向
            Vector3d elevationViewDir = pElevationModelView->GetViewDirection();
            elevationViewDir.Normalize();
            //立面视图视图右方向
            Vector3d elevationViewDirRight = pElevationModelView->GetRightDirection();
            elevationViewDirRight.Normalize();
            //立面视图视图上方向（Z向）
            Vector3d elevationViewDirUp = pElevationModelView->GetUpDirection();
            elevationViewDirUp.Normalize();

            //创建临时水平面：平面过视图原点，法向为Z向（立面视图上方向）
            OwnerPtr<IPlane> opTmpLevelPlane = IPlane::Create(elevationViewOrigin, elevationViewDirUp);
            DBG_WARN_AND_RETURN_VOID_UNLESS(opTmpLevelPlane, L"invalid opTmpLevelPlane",L"GDMPLab",L"2024-03-30");

            //将选中的空间点（pos）投影至临时水平面
            Vector3d pointProjectedOnPlane;
            Vector2d uvParameter;
            AlgorithmProject::Project(pos, opTmpLevelPlane.get(), uvParameter, pointProjectedOnPlane);

            //在临时水平面上，判断空间点的投影点在 立面视图视图方向 的左侧还是右侧
            enum class AuxiliaryPointSideType
            {
                LeftSideType,
                RightSideType
            } sideType;
            {
                //向量1：视图方向的向量
                Vector2d dir1 = elevationViewDir.Vec2d();
                //向量2：视图原点到投影点的向量
                Vector2d dir2 = (pointProjectedOnPlane - elevationViewOrigin).Vec2d();
                dir1.Normalize();
                dir2.Normalize();

                //向量1（逆时针）旋转至向量2，若角度小于180度为左侧，大于180度为右侧
                double angle = Vector2dUtils::GetAngle(dir1, dir2);
                sideType = MathUtils::IsLessThan(angle, Constants::MATH_PI, Constants::ANGLE_EPS) ? AuxiliaryPointSideType::LeftSideType : AuxiliaryPointSideType::RightSideType;
            }

            //计算投影点到视图方向向量所在直线上的距离
            double distance;
            //立面标记夹点距离立面标记中心的极限距离（等腰直角三角形斜边的1/2）
            double triangleSlopeLineHalf = ((double)ElevationViewSymbolNewTriangleCathetus) * sqrt(2) / 2.0;
            //如果夹点为起点且投影点在左侧 或者 夹点为终点且投影点在右侧，则计算夹点到 视图方向向量所在直线 上的距离
            if ((AuxiliaryPointStartEndPointType::StartPointType == (AuxiliaryPointStartEndPointType)pointIndex && AuxiliaryPointSideType::LeftSideType == sideType) ||
                (AuxiliaryPointStartEndPointType::EndPointType == (AuxiliaryPointStartEndPointType)pointIndex && AuxiliaryPointSideType::RightSideType == sideType))
            {
                OwnerPtr<ICurve3d> pElevationModelViewDirLine = ILine3d::Create(elevationViewOrigin, elevationViewDir);

                Vector3d minDisPtOnCurve;
                bool bOk = AlgorithmMinimalDistance::Calculate(pElevationModelViewDirLine.get(), pointProjectedOnPlane, minDisPtOnCurve, false, nullptr, distance);
                DBG_WARN_AND_RETURN_VOID_UNLESS(bOk, L"invalid distance",L"GDMPLab",L"2024-03-30");

                distance = distance > triangleSlopeLineHalf ? distance : triangleSlopeLineHalf;
            }
            //否则距离始终为极限距离
            else
            {
                distance = triangleSlopeLineHalf;
            }

            //更新裁剪框范围
            double leftOffset;
            double rightOffset;
            double upOffset;
            double downOffset;
            pViewClipRange->GetRectViewClipRange(leftOffset, rightOffset, upOffset, downOffset);

            if (AuxiliaryPointStartEndPointType::StartPointType == (AuxiliaryPointStartEndPointType)pointIndex)
            {
                leftOffset = distance;
            }
            else if (AuxiliaryPointStartEndPointType::EndPointType == (AuxiliaryPointStartEndPointType)pointIndex)
            {
                rightOffset = distance;
            }
            pViewClipRange->UpdateRectViewClipRange(leftOffset, rightOffset, upOffset, downOffset);
        }

#pragma endregion IElementPositionPoints 接口

    public: //实现NdbObject接口
        virtual NdbObject* GetTopOwnerObject() const override
        {
            return nullptr;
        }

#pragma region Inner Tools
    private:
        IElementPositionPoints* GetDefaultPositonPoints()
        {
            return GetDefaultPositonPointsFW__().get();
        }

        const IElementPositionPoints* GetDefaultPositonPoints() const
        {
            return GetDefaultPositonPoints__().get();
        }

        IModelView* GetElevationModelViewOfOwnerSymbol() const
        {
            const IGenericElement* pOwnerElement = quick_cast<IGenericElement>(GetOwnerElement());
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pOwnerElement, L"invalid pOwnerElement",L"GDMPLab",L"2024-03-30");
            const ElevationViewSymbolNew *pSymbol = quick_cast<ElevationViewSymbolNew>(pOwnerElement->GetExternalObject());
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pSymbol, L"invalid pSymbol",L"GDMPLab",L"2024-03-30");
            return pSymbol->GetElevationModelView();
        }
#pragma endregion Inner Tools
    };
    DBOBJECT_DATA_DEFINE(ElevationViewSymbolNewPositionPoints)
    {
        SetDefaultPositonPoints__(nullptr);
    }
}

DBOBJECT_DATA_DEFINE(ElevationViewSymbolNew)
{
    m_pOwnerElement = nullptr;
    SetElevationModelViewId__(ElementId::InvalidID);
    SetMarkChanged__(true);
}

IMPLEMENT_REGEN_FUNCTIONS(gcmp, ElevationViewSymbolNew, ModelViewRangeUpdated)

IElevationViewSymbolNew* ElevationViewSymbolNew::Create(IDocument *pDoc, ElementId elevationModelViewId)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"invalid pDoc",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(elevationModelViewId.IsValid(), L"invalid elevationModelViewId",L"GDMPLab",L"2024-03-30");
    OwnerPtr<ElevationViewSymbolNew> opSymbol = NEW_AS_OWNER_PTR(ElevationViewSymbolNew);
    ElevationViewSymbolNew* pSymbol = opSymbol.get();

    IGenericElement* pGenericElement = IGenericElement::Create(pDoc, TransferOwnership(opSymbol), ElevationViewSymbolNew::GetClassId().GetGuid());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"invalid pGenericElement",L"GDMPLab",L"2024-03-30");

    pGenericElement->SetPositionPoints(NEW_AS_OWNER_PTR(ElevationViewSymbolNewPositionPoints, pGenericElement));
    if (pGenericElement->GetElementParameters()) {
        pGenericElement->GetElementParameters()->SetElementParametersCustomizer(
            NEW_AS_OWNER_PTR(ElevationViewSymbolNewParametersCustomizer));
    }
    pGenericElement->SetElementTransformationComponent(NEW_AS_OWNER_PTR(ElevationViewSymbolNewTransformationComponent));
    pGenericElement->SetElementRegenerationComponent(NEW_AS_OWNER_PTR(ElevationViewSymbolNewRegenerationBehavior, pGenericElement));
    pGenericElement->SetViewSpecificShapeComponent(
        NEW_AS_OWNER_PTR(ElevationViewSymbolNewViewSpecificShapeComponent));

    IElementBasicInformation *pBasicInfo = pGenericElement->GetBasicInformation();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pBasicInfo, L"invalid pBasicInfo",L"GDMPLab",L"2024-03-30");
    pBasicInfo->SetCategoryUid(BuiltInCategoryUniIdentities::BICU_ELEVATION_VIEW_SYMBOL);
    pBasicInfo->SetClassificationUid(ElevationViewSymbolNew::GetClassId().GetGuid());
    pBasicInfo->SetDefaultTypeName(GBMP_TR(L"立面视图"));
    pBasicInfo->SetImplementationUid(ElevationViewSymbolNew::GetImplementationUid());

    pSymbol->SetElevationModelViewId(elevationModelViewId);

    IModelView *pElevationModelView = quick_cast<IModelView>(pDoc->GetElement(elevationModelViewId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElevationModelView, L"invalid pElevationModelView",L"GDMPLab",L"2024-03-30");
    pElevationModelView->SetViewSymbolId(pGenericElement->GetElementId());

    // 转发视图名称的检查行为
    IElementParameters *pGenericElementParameters = pGenericElement->GetElementParameters();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElementParameters, L"invalid pGenericElementParameters",L"GDMPLab",L"2024-03-30");
    pGenericElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(ElevationViewSymbolNewNameParameterOverride, pGenericElement));

    return quick_cast<IElevationViewSymbolNew>(pGenericElement->GetExternalObject());
}

gcmp::UniIdentity gcmp::ElevationViewSymbolNew::GetImplementationUid()
{
    static UniIdentity s_implementationUid = UniIdentity::Create(
        GuidUtils::FromString(L"{494DD7A1-C42D-49D7-8D58-5787707EEEFF}"), L"ElevationViewSymbolNew");
    return s_implementationUid;
}

#pragma region IExternalObject 接口
bool ElevationViewSymbolNew::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    return true;
}

const IElement* ElevationViewSymbolNew::GetOwnerElement() const
{
    return m_pOwnerElement;
}

IElement* ElevationViewSymbolNew::GetOwnerElement()
{
    return m_pOwnerElement;
}

NdbObject* ElevationViewSymbolNew::GetTopOwnerObject() const
{
    return quick_cast<NdbObject>(const_cast<IElement*>(GetOwnerElement()));
}

void ElevationViewSymbolNew::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{
}

void ElevationViewSymbolNew::ReportParents(IElementParentReporter& reporter) const
{
    reporter.ReportStrong(GetModelViewId());
}

bool ElevationViewSymbolNew::FinishEditing()
{
    return true;
}
#pragma endregion IExternalObject 接口

#pragma region IElevationViewSymbolNew 接口
ElementId ElevationViewSymbolNew::GetModelViewId() const
{
    return GetElevationModelViewId__();
}

ElementId ElevationViewSymbolNew::GetOwnerElementId() const
{
    if (!m_pOwnerElement)
    {
        return ElementId::InvalidID;
    }
    return m_pOwnerElement->GetElementId();
}

#pragma endregion IElevationViewSymbolNew 接口

#pragma region 其他
OwnerPtr<IGraphicsElementShape> ElevationViewSymbolNew::CreateModelViewElementShape(const IModelView* pModelView) const
{
    IModelView *pElevationModelView = GetElevationModelView();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElevationModelView, L"invalid pElevationModelView",L"GDMPLab",L"2024-03-30");

    double viewScale = 1;
    Vector3d LevelPlaneUDir;
    Vector3d LevelPlaneVDir;
    Vector3d LevelPlaneWDir;
    bool bOk = GetModelViewViewScaleAndNormalizedUVWDirection(pModelView, viewScale, LevelPlaneUDir, LevelPlaneVDir, LevelPlaneWDir);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"invalid pModelView",L"GDMPLab",L"2024-03-30");

    Vector3d viewPoint3d;
    Vector3d viewDir3d;
    bOk = GetElevationModelViewViewPointAndViewDirectionProjectedOnLevelModelView(pElevationModelView, pModelView, viewPoint3d, viewDir3d);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"invalid pModelView",L"GDMPLab",L"2024-03-30");
    IGraphicsStyleManager* pStyleManager = GetDocument()->GetGraphicsStyleManager();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStyleManager, L"IGraphicsStyleManager为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IGraphicsElementShape> opGrep = IGraphicsElementShape::Create(GraphicsRenderLayer::Annotation);
    //圆
    {
        double dRadius = (double)ElevationViewSymbolNewCircleRadius;                  // 圆半径
        OwnerPtr<IGraphicsArc> opCircle = IGraphicsArc::CreateByCenterAndRadius(viewPoint3d, LevelPlaneUDir, LevelPlaneVDir, dRadius, 0, gcmp::Constants::MATH_2PI, true);

        opCircle->SetGraphicsStyleId(pStyleManager->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_ELEVATION_VIEW_SYMBOL));
        opGrep->AddChild(TransferOwnership(opCircle));
    }
    //三角形
    {
        double triangleSlopeLineHalf = ((double)ElevationViewSymbolNewTriangleCathetus) * sqrt(2) / 2.0;
        Vector3d trianglePoint_1 = viewPoint3d + viewDir3d*triangleSlopeLineHalf;
        Vector3d trianglePoint_2 = viewPoint3d + (Vector3dUtils::RotateVectorAroundAxis(viewDir3d, LevelPlaneWDir, Constants::MATH_PI_2))*triangleSlopeLineHalf;
        Vector3d trianglePoint_3 = viewPoint3d + (Vector3dUtils::RotateVectorAroundAxis(viewDir3d, LevelPlaneWDir, -Constants::MATH_PI_2))*triangleSlopeLineHalf;

        OwnerPtr<IGraphicsLine> opLine_12 = IGraphicsLine::Create(trianglePoint_1, trianglePoint_2);
        OwnerPtr<IGraphicsLine> opLine_13 = IGraphicsLine::Create(trianglePoint_1, trianglePoint_3);
        OwnerPtr<IGraphicsLine> opLine_23 = IGraphicsLine::Create(trianglePoint_2, trianglePoint_3);
        opLine_12->SetGraphicsStyleId(pStyleManager->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_ELEVATION_VIEW_SYMBOL));
        opLine_13->SetGraphicsStyleId(pStyleManager->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_ELEVATION_VIEW_SYMBOL));
        opLine_23->SetGraphicsStyleId(pStyleManager->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_ELEVATION_VIEW_SYMBOL));

        opGrep->AddChild(TransferOwnership(opLine_12));
        opGrep->AddChild(TransferOwnership(opLine_13));
        opGrep->AddChild(TransferOwnership(opLine_23));
    }
    //文字
    {
        float fFontHeight = (float)ElevationViewSymbolNewFontsHeight;      // 文本字体高度
        std::wstring name = pElevationModelView->GetName();
        Vector3d posViewName(viewPoint3d.X(), viewPoint3d.Y(), viewPoint3d.Z());
        OwnerPtr<IGraphicsText> opNameText = IGraphicsText::Create(L"", posViewName, LevelPlaneUDir, LevelPlaneWDir, fFontHeight, name.c_str(), AnchorAlignmentType::Center);
        opNameText->SetGraphicsStyleId(pStyleManager->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_ELEVATION_VIEW_SYMBOL));
        opNameText->SetTextPrimitiveType(TextPrimitiveType::Triangle);
        opGrep->AddChild(TransferOwnership(opNameText));
    }
    return TransferOwnership(opGrep);
}

bool ElevationViewSymbolNew::MakeTransform(const Matrix4d& matrix)
{
    IModelView *pElevationModelView = GetElevationModelView();

    Vector3d elevationModelViewPoint = pElevationModelView->GetOrigin();
    Vector3d moveVector = matrix.GetTranslation();
    pElevationModelView->SetOrigin(elevationModelViewPoint + moveVector);

    //更改标志位以触发视图刷新
    MarkChanged();
    return true;
}

void ElevationViewSymbolNew::MarkChanged()
{
    SetMarkChanged__(!GetMarkChanged__());
}

IDocument* ElevationViewSymbolNew::GetDocument() const
{
    if (!m_pOwnerElement)
    {
        return nullptr;
    }
    return m_pOwnerElement->GetDocument();
}

IModelView* ElevationViewSymbolNew::GetElevationModelView() const
{
    IDocument* pDoc = GetDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"invalid pDoc",L"GDMPLab",L"2024-03-30");
    return quick_cast<IModelView>(pDoc->GetElement(GetElevationModelViewId__()));
}

#pragma endregion 其他

void ElevationViewSymbolNew::SetElevationModelViewId(const ElementId& viewId)
{
    SetElevationModelViewId__(viewId);
    SubscribeModelViewEvent();
}

bool ElevationViewSymbolNew::GetElevationModelViewViewPointAndViewDirectionProjectedOnLevelModelView(const IModelView *pElevationModelView, const IModelView* pLevelModelView, Vector3d &viewPoint, Vector3d &viewDir) const
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElevationModelView, L"invalid pModelView",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pLevelModelView, L"invalid pModelView",L"GDMPLab",L"2024-03-30");

    Vector3d elevationModelViewPoint3d = pElevationModelView->GetOrigin();
    Vector3d elevationModelViewDir3d = pElevationModelView->GetViewDirection();

    OwnerPtr<IPlane> pLevelWorkPlane = pLevelModelView->GetWorkPlane();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pLevelWorkPlane, L"invalid pDesWorkPlane",L"GDMPLab",L"2024-03-30");

    Vector2d uvParameter;
    AlgorithmProject::Project(elevationModelViewPoint3d, pLevelWorkPlane.get(), uvParameter, viewPoint);

    //注：GProjection::ProjectVector现实现有误？，故现将三维点投影至平面，取二维作方向向量
    //viewDir = Vector3d(GProjection::ProjectVector(pLevelWorkPlane.get(), elevationModelViewDir3d), 0);
    AlgorithmProject::Project(elevationModelViewDir3d, pLevelWorkPlane.get(), uvParameter, viewDir);
    viewDir = Vector3d(viewDir.Vec2d(), 0);
    viewDir.Normalize();

    return true;
}

bool ElevationViewSymbolNew::GetModelViewViewScaleAndNormalizedUVWDirection(const IModelView *pModelView, double &viewScale, Vector3d &uDir, Vector3d &vDir, Vector3d &wDir) const
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"invalid pModelView",L"GDMPLab",L"2024-03-30");

    uDir = pModelView->GetRightDirection();
    vDir = pModelView->GetUpDirection();
    wDir = pModelView->GetViewDirection();

    uDir.Normalize();
    vDir.Normalize();
    wDir.Normalize();
    wDir = -wDir;

    return true;
}

bool ElevationViewSymbolNew::SubscribeModelViewEvent()
{
    IModelView* pModelView = GetElevationModelView();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"invalid pModelView",L"GDMPLab",L"2024-03-30");

    OwnerPtr<AssociatedModelViewEventHandler> opModelViewEventHandler = NEW_AS_OWNER_PTR(AssociatedModelViewEventHandler, this);
    pModelView->GetModelViewEvent()->Add(opModelViewEventHandler.get());
    SetModelViewEventHandler__(TransferOwnership(opModelViewEventHandler));

    return true;
}

bool ElevationViewSymbolNew::UnsubscribeModelViewEvent()
{
    IModelView* pModelView = GetElevationModelView();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"invalid pModelView",L"GDMPLab",L"2024-03-30");

    if (pModelView)
    {
        pModelView->GetModelViewEvent()->Delete(this->GetModelViewEventHandlerFW__().get());
    }

    return true;
}


REGISTER_IMPLEMENTATION_UID_TREE_RELATION(IGenericElement, ElevationViewSymbolNew);
